#include "Log.h"
#include "I2C_Ctrl.h"
#include "Systick_Ctrl.h"

static uint32_t Waitcounts = 0;

void I2C_Config(void)
{
    /* configure I2C clock */
    i2c_clock_config(I2C_CH, I2C_SPEED, I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C_CH, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C_DEF_ADDR);
    /* enable I2C0 */
    i2c_enable(I2C_CH);
    /* enable acknowledge */
    i2c_ack_config(I2C_CH, I2C_ACK_ENABLE);

    Systick_Delay(100);
}

void I2C_Restart(void)
{
    i2c_disable(I2C_CH);
    I2C_Config();
}

void I2C_BusIsIdle(void)
{
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_I2CBSY), "Testing I2C Bus Idle Failed.");
    return;
__error__:
    I2C_Restart();
}

void I2C_BytesWrite(uint8_t devAddr, uint8_t subAddr, uint8_t* pByte, uint8_t NumByteToWrite)
{
    i2c_ack_config(I2C_CH, I2C_ACK_ENABLE);

    /* The software must wait until I2C Bus is idle */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_I2CBSY), "I2C Write wait I2C Bus's idle failed.");

    /* Send STRAT condition */
    i2c_start_on_bus(I2C_CH);

    /* Wait until SBSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_SBSEND), "I2C Write wait SBSEND failed.");

    /* Send 7bit Device address for write */
    i2c_master_addressing(I2C_CH, devAddr, I2C_TRANSMITTER);

    /* Wait until ADDSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_ADDSEND), "I2C Write wait ADDREND failed");

    /* clear ADDSEND bit */
    i2c_flag_clear(I2C_CH, I2C_FLAG_ADDSEND);

    /* Wait until the transmit data buffer is empty */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_TBE) != SET, "I2C Write wait data buffer empty failed");

    /* Send the EEPROM's internal address to write to */
    i2c_data_transmit(I2C_CH, subAddr);

    /* Wait until BTC bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_TBE), "I2C Write wait SUBADDREND failed");

    while(NumByteToWrite > 0)
    {
        /* Send the byte to be written */
        i2c_data_transmit(I2C_CH, *pByte);
        pByte++; NumByteToWrite--;
        /* Wait until BTC bit is set and clear it */
        I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_TBE), "I2C Write wait TRANSMITTED failed");
    }

    /* Send STOP condition */
    i2c_stop_on_bus(I2C_CH);

    return;
__error__:
    I2C_Restart();
}

void I2C_ByteWrite(uint8_t devAddr, uint8_t subAddr, uint8_t Byte)
{
    
    i2c_ack_config(I2C_CH, ENABLE);

    /* The software must wait until I2C Bus is idle */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_I2CBSY), "I2C Write wait I2C Bus's idle failed.");

    /* Send STRAT condition */
    i2c_start_on_bus(I2C_CH);

    /* Wait until SBSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_SBSEND), "I2C Write wait SBSEND failed.");

    /* Send 7bit Device address for write */
    i2c_master_addressing(I2C_CH, devAddr, I2C_TRANSMITTER);

    /* Wait until ADDSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_ADDSEND), "I2C Write wait ADDREND failed");

    /* clear ADDSEND bit */
    i2c_flag_clear(I2C_CH, I2C_FLAG_ADDSEND);

    /* Wait until the transmit data buffer is empty */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_TBE) != SET, "I2C Write wait data buffer empty failed");

    /* Send the EEPROM's internal address to write to */
    i2c_data_transmit(I2C_CH, subAddr);

    /* Wait until BTC bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_TBE), "I2C Write wait SUBADDREND failed");

    /* Send the byte to be written */
    i2c_data_transmit(I2C_CH, Byte);

    /* Wait until BTC bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_TBE), "I2C Write wait TRANSMITTED failed");

    /* Send STOP condition */
    i2c_stop_on_bus(I2C_CH);

    return;
__error__:
    I2C_Restart();
}


void I2C_BytesRead(uint8_t devAddr, uint8_t subAddr, uint8_t* pBytes, uint16_t NumByteToRead)
{
    uint32_t ReceivedTimes = 0;

    i2c_ack_config(I2C_CH, ENABLE);

    /* While the bus is busy */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_I2CBSY), "I2C Read Wait I2C Bus's idle failed.");

    /* Send START condition */
    i2c_start_on_bus(I2C_CH);

    /* Wait until the SBSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_SBSEND), "I2C Read wait SBSEND failed.");

    /* Send 7bit Device address for write */
    i2c_master_addressing(I2C_CH, devAddr, I2C_TRANSMITTER);

    /* Wait until the ADDSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_ADDSEND), "I2C Read wait ADDREND1 failed");

    /* clear ADDSEND bit */
    i2c_flag_clear(I2C_CH, I2C_FLAG_ADDSEND);

    /* Wait until the transmit data buffer is empty */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_TBE) != SET, "I2C Read wait data buffer empty failed");

    /* Set again the PE bit */
    i2c_enable(I2C_CH);

    /* Send the Sub Address to write to */
    i2c_data_transmit(I2C_CH, subAddr);

    /* Wait until the BTC bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_TBE), "I2C Read wait SUBADDREND failed");

    /* Send STRAT condition a second time */
    i2c_start_on_bus(I2C_CH);

    /* Wait until the SBSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_SBSEND), "I2C Write wait SBSEND again failed.");

    /* Send 7bit Device address for read */
    i2c_master_addressing(I2C_CH, devAddr, I2C_RECEIVER);

    /* While there is data to be read */
    while(NumByteToRead)
    {
        if(NumByteToRead == 1)
        {
            /* wait until the second last data byte is received into the shift register */
            I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_BTC), "I2C Read wait SECONDLAST failed");
            /* disable acknowledge */
            i2c_ack_config(I2C_CH, DISABLE);
        }

        /* Wait until the RBNE bit is set and clear it */
        if(i2c_flag_get(I2C_CH, I2C_FLAG_RBNE))
        {
            ReceivedTimes = 0;
            /* Read a byte from the EEPROM */
            *pBytes = i2c_data_receive(I2C_CH);

            /* Point to the next location where the byte read will be saved */
            pBytes++;

            /* Decrement the read bytes counter */
            NumByteToRead--;
        }
        else
        {
            ReceivedTimes++;
            if(ReceivedTimes > I2C_MAX_WAIT_TIMES)
            {
                ERR_PRINT(("I2C Read Timeout!\r\n"));
                goto __error__;
            }
        }
    }

    /* Send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C_CH);
    I2C_WAIT(((I2C_CTL0(I2C_CH) & I2C_CTL0_STOP)), "I2C Reads waiting done failed!");
    /* Enable Acknowledgement to be ready for another reception */
    i2c_ack_config(I2C_CH, ENABLE);
    return;
__error__:
    I2C_Restart();
}

uint8_t I2C_ByteRead(uint8_t devAddr, uint8_t subAddr)
{
    uint8_t Byte;

    i2c_ack_config(I2C_CH, ENABLE);

    /* While the bus is busy */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_I2CBSY), "I2C Read Wait I2C Bus's idle failed.");

    /* Send START condition */
    i2c_start_on_bus(I2C_CH);

    /* Wait until the SBSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_SBSEND), "I2C Read wait SBSEND failed.");

    /* Send 7bit Device address for write */
    i2c_master_addressing(I2C_CH, devAddr, I2C_TRANSMITTER);

    /* Wait until the ADDSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_ADDSEND), "I2C Read wait ADDREND1 failed");

    /* clear ADDSEND bit */
    i2c_flag_clear(I2C_CH, I2C_FLAG_ADDSEND);

    /* Wait until the transmit data buffer is empty */
    I2C_WAIT(i2c_flag_get(I2C_CH, I2C_FLAG_TBE) != SET, "I2C Read wait data buffer empty failed");

    /* Set again the PE bit */
    i2c_enable(I2C_CH);

    /* Send the Sub Address to write to */
    i2c_data_transmit(I2C_CH, subAddr);

    /* Wait until the BTC bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_TBE), "I2C Read wait SUBADDREND failed");

    /* Send STRAT condition a second time */
    i2c_start_on_bus(I2C_CH);

    /* Wait until the SBSEND bit is set and clear it */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_SBSEND), "I2C Write wait SBSEND again failed.");

    /* Send 7bit Device address for read */
    i2c_master_addressing(I2C_CH, devAddr, I2C_RECEIVER);

    /* N=1,Reset ACKEN bit before clearing ADDRSEND bit */
    i2c_ack_config(I2C_CH, DISABLE);

    /* Wait until the reception data register is not empty */
    I2C_WAIT(!i2c_flag_get(I2C_CH, I2C_FLAG_RBNE), "I2C Read wait RECEICED failed");

    /* Read a byte */
    Byte = i2c_data_receive(I2C_CH);

    /* Send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C_CH);
    I2C_WAIT(((I2C_CTL0(I2C_CH) & I2C_CTL0_STOP)), "I2C Reads waiting done failed!");
    /* Enable Acknowledgement to be ready for another reception */
    i2c_ack_config(I2C_CH, ENABLE);

    return Byte;
__error__:
    I2C_Restart();
    return 0xFF;
}
